#include "WeightedCardRange.h"
#include <sstream>
#include <algorithm>
#include <numeric>
#include <stdexcept>
#include <cassert>
#include <mutex>
#include <iostream>
#include <iomanip>

using namespace std;

namespace omp {

WeightedCardRange::WeightedCardRange(const string& expr, bool normalize, bool debugOutput)
{
    mDebugOutput = debugOutput;
    stringstream ss(expr);
    string token;
    while (getline(ss, token, ',')) {
        auto pos = token.find(':');
        string hand = token.substr(0, pos);
        double weight = 1.0;
        if (pos != string::npos) {
            try {
                weight = stod(token.substr(pos + 1));
            } catch (...) {
                weight = 1.0;
            }
        }
        if (weight <= 1e-10) {
            continue; // 跳过权重为 0 的组合
        }
        CardRange cr(hand);
        for (const auto& combo : cr.combinations()) {
            mWeightedCombos.emplace_back(combo, weight);
            // 保存原始手牌字符串表示，用于区分具体牌型和通用牌型
            mOriginalHandStrings[combo] = hand;
        }
    }
    

    double total = 0;
    for (const auto& p : mWeightedCombos) total += p.second;
    if (mDebugOutput) {
        std::cout << "[DEBUG] Total weight before normalization: " << total << std::endl;
        std::cout << "mWeightedCombos size: " << mWeightedCombos.size() << std::endl;
    }
    // 归一化权重
    static int constructorCount = 0;
    constructorCount++;
    // std::cout << "[DEBUG] Constructor called " << constructorCount << " times" << std::endl;
    
    if (normalize) {
        if (total > 1e-10) { 
            for (auto& p : mWeightedCombos) p.second /= total;
        } else {
            for (auto& p : mWeightedCombos) p.second = 1.0 / mWeightedCombos.size();
        }
        double totalAfter = 0;
        for (const auto& p : mWeightedCombos) totalAfter += p.second;
        if (mDebugOutput) std::cout << "[DEBUG] Total weight after normalization: " << totalAfter << std::endl;
    }

    // // 在WeightedCardRange.cpp的构造函数中，填充mWeightMap时：
    // for (const auto& combo : mWeightedCombos) {
    //     // 标准化手牌顺序
    //     std::array<uint8_t, 2> normalizedCombo;
    //     normalizedCombo[0] = std::min(combo.first[0], combo.first[1]);
    //     normalizedCombo[1] = std::max(combo.first[0], combo.first[1]);
    //     mWeightedCombos.emplace_back(normalizedCombo, combo.second);
    // }
    // // mWeightedCombos = std::move(normalizedCombo);
    // // 直接填充mWeightMap，CardRange已经保证手牌顺序正确
    for (const auto& combo : mWeightedCombos) {
        mWeightMap[combo.first] = combo.second;  
    }

    if (mDebugOutput) {
    for (const auto& p : mWeightedCombos) {
        std::cout << "Parsed: " << CardRange::handToString(p.first) << " weight: " << p.second << std::endl;
    }
    // // 输出标准化后的mWeightMap内容
    // std::cout << "mWeightMap size: " << mWeightMap.size() << std::endl;
    // for (const auto& entry : mWeightMap) {
    //     std::array<uint8_t, 2> hand = entry.first;
    //     std::string handStr = CardRange::handToString(hand);
    //     std::cout << "  Normalized: " << handStr << " weight: " << entry.second << std::endl;
    // }
}
    // 输出解析后的 mWeightedCombos
    // std::cout << "[DEBUG] Parsed mWeightedCombos:" << std::endl;
    // for (const auto& p : mWeightedCombos) {
    //     std::cout << CardRange::handToString(p.first) << ": " << p.second << std::endl;
    // }
}
WeightedCardRange::WeightedCardRange(const WeightedCardRange& other) :
    mDebugOutput(other.mDebugOutput), 
    mWeightedCombos(other.mWeightedCombos), 
    mOriginalHandStrings(other.mOriginalHandStrings),
    mRng(std::random_device{}()), 
    mDist(0.0, 1.0),
    mWeightMap(other.mWeightMap)
    {
    // if (mDebugOutput) {
    //     // 添加原对象权重状态检查
    //     double sum = 0;
    //     for (const auto& p : other.mWeightedCombos) sum += p.second;
    //     std::cout << "[Copy Constructor] Original weight sum: " << sum << std::endl;
    //     std::cout << std::fixed << std::setprecision(10);
    //     for (const auto& p : mWeightedCombos) {
    //         std::cout << "Copied combo: " << CardRange::handToString(p.first) 
    //             << ", weight: " << p.second << std::endl;    
    //         }
    //     std::cout.unsetf(std::ios::fixed);
    //     }
    }
double WeightedCardRange::weight(const std::array<uint8_t,2>& hand) const {
    // CardRange::addCombo 已经保证手牌是降序排列，直接使用即可
    auto it = mWeightMap.find(hand);
    if (it != mWeightMap.end()) {
        return it->second;
    }
    return 0.0;
}

string WeightedCardRange::toString() const
{
    stringstream ss;
    bool first = true;
    for (const auto& combo : mWeightedCombos) {
        if (!first) ss << ",";
        ss << CardRange::handToString(combo.first) << ":" << combo.second;
        first = false;
    }
    return ss.str();
}


array<uint8_t,2> WeightedCardRange::sample() const
{
    // 提取权重
    vector<double> weights;
    weights.reserve(mWeightedCombos.size());
    for (const auto& p : mWeightedCombos) weights.push_back(p.second);

    // 累加权重并检查总和
    vector<double> acc(weights.size());
    partial_sum(weights.begin(), weights.end(), acc.begin());

    // // 打印权重和累加和
    std::cout << std::fixed << std::setprecision(6);
    // std::cout << "[DEBUG] Weights: ";
    // for (double w : weights) {
    //     std::cout << w << " ";
    // }
    // std::cout << std::endl;
    // std::cout << "[DEBUG] Accumulated weights: ";
    // for (double a : acc) {
    //     std::cout << a << " ";
    // }
    // std::cout << std::endl;

    // 生成随机数并找到对应的组合
    double total_weight = acc.empty() ? 0 : acc.back();
    double r = mDist(mRng) * total_weight;
    auto it = lower_bound(acc.begin(), acc.end(), r);
    size_t idx = distance(acc.begin(), it);
    if (idx >= mWeightedCombos.size()) idx = mWeightedCombos.size() - 1;
    return mWeightedCombos[idx].first;
    }
}